/// n 位有符号数扩展成 i32
pub fn in_to_i32(raw: u32, n: i32) -> i32 {
    let mask: u32 = 1 << (n - 1);
    let sign = mask & raw;
    if sign == 0 {
        raw as i32
    } else {
        (raw | u32::MAX << n) as i32
    }
}

/// n 位有符号数扩展成 i64
pub fn in_to_i64(raw: u64, n: i32) -> i64 {
    let mask: u64 = 1 << (n - 1);
    let sign = mask & raw;
    if sign == 0 {
        raw as i64
    } else {
        (raw | (u64::MAX << n)) as i64
    }
}

pub trait TruncateTo<T> {
    fn truncate_to(self) -> T;
}

impl TruncateTo<u64> for u64 {
    fn truncate_to(self) -> u64 {
        self
    }
}

impl TruncateTo<u32> for u64 {
    fn truncate_to(self) -> u32 {
        (self & u32::MAX as u64) as u32
    }
}

impl TruncateTo<u16> for u64 {
    fn truncate_to(self) -> u16 {
        (self & u16::MAX as u64) as u16
    }
}
impl TruncateTo<u8> for u64 {
    fn truncate_to(self) -> u8 {
        (self & u8::MAX as u64) as u8
    }
}
#[cfg(test)]
mod test {
    use super::*;
    #[test]
    fn test_2i32() {
        let a: u32 = 0b1000;
        let ia = in_to_i32(a, 4);
        assert_eq!(ia, -8);

        let a: u32 = 0b1011;
        let ia = in_to_i32(a, 4);
        assert_eq!(ia, -5);

        let a: u32 = 10;
        let ia = in_to_i32(a, 13);
        assert_eq!(ia, 10);

        let a: u32 = 0;
        let ia = in_to_i32(a, 13);
        assert_eq!(ia, 0);
    }

    #[test]
    fn test_2i64() {
        let a: u64 = 0b1000;
        let ia = in_to_i64(a, 4);
        assert_eq!(ia, -8);

        let a: u64 = 0b1011;
        let ia = in_to_i64(a, 4);
        assert_eq!(ia, -5);

        let a: u64 = 10;
        let ia = in_to_i64(a, 13);
        assert_eq!(ia, 10);

        let a: u64 = 0;
        let ia = in_to_i64(a, 13);
        assert_eq!(ia, 0);
    }
}
